<!DOCTYPE html>
<html lang="en">
<head>
<title>HTML5浪漫爱心表白动画DEMO演示</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">

<style>
	body {
		font-family: Monospace;
		background-color: #f0f0f0;
		margin: 0px;
		overflow: hidden;
	}
</style>

</head>
<body>


<script src="js/nb.js"></script>

<script src="js/Projector.js"></script>
<script src="js/CanvasRenderer.js"></script>

<script src="js/tween.min.js"></script>
<script src="js/Sparks.js"></script>

<!-- load the font file from canvas-text -->

<script src="js/helvetiker_regular.typeface.js"></script>


<script>

	var container;

	var camera, scene, renderer;

	var group, text, plane;

	var targetRotation = 0;
	var targetRotationOnMouseDown = 0;

	var mouseX = 0;
	var mouseXOnMouseDown = 0;

	var windowHalfX = window.innerWidth / 2;
	var windowHalfY = window.innerHeight / 2;

	var heartShape, particleCloud, sparksEmitter, emitterPos;
	var _rotation = 0;
	var timeOnShapePath = 0;

	init();
	animate();

	function init() {

		container = document.createElement('div');
		document.body.appendChild(container);


		//相机
		camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 1000);
		camera.position.set(0, 150, 800);

		//场景
		scene = new THREE.Scene();

		group = new THREE.Group();
		scene.add(group);

		// Get text from hash

		var string = "yun";
		var hash = document.location.hash.substr(1);

		if (hash.length !== 0) {

			string = hash;

		}
		
		var text3d = new THREE.TextGeometry(string, {
			size: 80,
			height: 20,
			curveSegments: 2,
			font: "helvetiker"

		});

	
		text3d.computeBoundingBox();
		var centerOffset = -0.5 * (text3d.boundingBox.max.x - text3d.boundingBox.min.x);

		var textMaterial = new THREE.MeshBasicMaterial({color: Math.random() * 0xffffff, overdraw: 0.5});

		text = new THREE.Mesh(text3d, textMaterial);

		// Potentially, we can extract the vertices or faces of the text to generate particles too.
		// Geo > Vertices > Position

		text.position.x = centerOffset;
		text.position.y = 100;
		text.position.z = 0;

		text.rotation.x = 0;
		text.rotation.y = Math.PI * 2;

		group.add(text);

		

		particleCloud = new THREE.Object3D(); // Just a group
		particleCloud.y = 800;
		group.add(particleCloud);

		// Create Particle Systems

		// Heart

		var x = 0, y = 0;

		heartShape = new THREE.Shape();

		heartShape.moveTo(x + 25, y + 25);
		heartShape.bezierCurveTo(x + 25, y + 25, x + 20, y, x, y);
		heartShape.bezierCurveTo(x - 30, y, x - 30, y + 35, x - 30, y + 35);
		heartShape.bezierCurveTo(x - 30, y + 55, x - 10, y + 77, x + 25, y + 95);
		heartShape.bezierCurveTo(x + 60, y + 77, x + 80, y + 55, x + 80, y + 35);
		heartShape.bezierCurveTo(x + 80, y + 35, x + 80, y, x + 50, y);
		heartShape.bezierCurveTo(x + 35, y, x + 25, y + 25, x + 25, y + 25);

		var hue = 0;

		var hearts = function(context) {

			context.globalAlpha = 0.5;
			var x = 0, y = 0;
			context.scale(0.05, -0.05); // Scale so canvas render can redraw within bounds
			context.beginPath();
			// From http://blog.burlock.org/html5/130-paths
			context.bezierCurveTo(x + 2.5, y + 2.5, x + 2.0, y, x, y);
			context.bezierCurveTo(x - 3.0, y, x - 3.0, y + 3.5, x - 3.0, y + 3.5);
			context.bezierCurveTo(x - 3.0, y + 5.5, x - 1.0, y + 7.7, x + 2.5, y + 9.5);
			context.bezierCurveTo(x + 6.0, y + 7.7, x + 8.0, y + 5.5, x + 8.0, y + 3.5);
			context.bezierCurveTo(x + 8.0, y + 3.5, x + 8.0, y, x + 5.0, y);
			context.bezierCurveTo(x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5);
			context.fill();
			context.lineWidth = 0.5; //0.05
			context.stroke();

		}

		var setTargetParticle = function() {

			var material = new THREE.SpriteCanvasMaterial({
				program: hearts
			});

			material.color.setHSL(hue, 1, 0.75);
			hue += 0.001;
			if (hue > 1)
				hue -= 1;

			particle = new THREE.Sprite(material);

			particle.scale.x = particle.scale.y = Math.random() * 40 + 40;
			particleCloud.add(particle);

			return particle;

		};

		var onParticleCreated = function(p) {

			p.target.position.copy(p.position);

		};

		var onParticleDead = function(particle) {

			particle.target.visible = false;
			particleCloud.remove(particle.target);

		};

		sparksEmitter = new SPARKS.Emitter(new SPARKS.SteadyCounter(160));

		emitterpos = new THREE.Vector3();

		sparksEmitter.addInitializer(new SPARKS.Position(new SPARKS.PointZone(emitterpos)));
		sparksEmitter.addInitializer(new SPARKS.Lifetime(0, 2));
		sparksEmitter.addInitializer(new SPARKS.Target(null, setTargetParticle));

		sparksEmitter.addInitializer(new SPARKS.Velocity(new SPARKS.PointZone(new THREE.Vector3(0, -50, 10))));

		// TOTRY Set velocity to move away from centroid

		sparksEmitter.addAction(new SPARKS.Age());
		//sparksEmitter.addAction(new SPARKS.Accelerate(0.2));
		sparksEmitter.addAction(new SPARKS.Move());
		sparksEmitter.addAction(new SPARKS.RandomDrift(50, 50, 2000));

		sparksEmitter.addCallback("created", onParticleCreated);
		sparksEmitter.addCallback("dead", onParticleDead);
		sparksEmitter.addCallback("updated", function(particle) {

			particle.target.position.copy(particle.position);

		});

		sparksEmitter.start();

		// End Particles


		renderer = new THREE.CanvasRenderer();
		renderer.setClearColor(0xf0f0f0);
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(window.innerWidth, window.innerHeight);
		container.appendChild(renderer.domElement);

		document.addEventListener('mousedown', onDocumentMouseDown, false);
		document.addEventListener('touchstart', onDocumentTouchStart, false);
		document.addEventListener('touchmove', onDocumentTouchMove, false);

		//

		window.addEventListener('resize', onWindowResize, false);

	}

	function onWindowResize() {

		windowHalfX = window.innerWidth / 2;
		windowHalfY = window.innerHeight / 2;

		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();

		renderer.setSize(window.innerWidth, window.innerHeight);

	}

	//

	document.addEventListener('mousemove', onDocumentMouseMove, false);

	function onDocumentMouseDown(event) {

		event.preventDefault();

		mouseXOnMouseDown = event.clientX - windowHalfX;
		targetRotationOnMouseDown = targetRotation;

		if (sparksEmitter.isRunning()) {

			sparksEmitter.stop();

		} else {

			sparksEmitter.start();

		}

	}

	function onDocumentMouseMove(event) {

		mouseX = event.clientX - windowHalfX;

		targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;

	}

	function onDocumentTouchStart(event) {

		if (event.touches.length == 1) {

			event.preventDefault();

			mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
			targetRotationOnMouseDown = targetRotation;

		}

	}

	function onDocumentTouchMove(event) {

		if (event.touches.length == 1) {

			event.preventDefault();

			mouseX = event.touches[ 0 ].pageX - windowHalfX;
			targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;

		}

	}

	//

	function animate() {//更新场景

		requestAnimationFrame(animate);

		render();

	}

	function render() {

		timeOnShapePath += 0.0337;

		if (timeOnShapePath > 1)
			timeOnShapePath -= 1;

		// TODO Create a PointOnShape Action/Zone in the particle engine
		var pointOnShape = heartShape.getPointAt(timeOnShapePath);

		emitterpos.x = pointOnShape.x * 5 - 100;
		emitterpos.y = -pointOnShape.y * 5 + 400;

		// Pretty cool effect if you enable this
		// particleCloud.rotation.y += 0.05;

		group.rotation.y += (targetRotation - group.rotation.y) * 0.05;
		renderer.render(scene, camera);
	}

</script>

</body>
</html>